using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;

public class SpineTouchConfigSOEditor : EditorWindow
{
    [SerializeField] private VisualTreeAsset m_VisualTreeAsset = default;

    public static SpineTouchConfigSO ConfigSO;

    //数据
    private SpineTouchConfigSO configSO = null;

    private const string ShowDefault = "SpineTouchConfigSOEditor_ShowDefault";
    private const string ShowLayer = "SpineTouchConfigSOEditor_ShowLayer";
    private const string ShowParameter = "SpineTouchConfigSOEditor_ShowParameter";
    private const string ShowEvent = "SpineTouchConfigSOEditor_ShowEvent";
    private const string ShowDetail = "SpineTouchConfigSOEditor_ShowDetail";

    private SerializedObject serializedObject;
    private SerializedProperty definitionListObject;
    private SerializedProperty defaultAnimObject;
    private SerializedProperty configGroupsObject;
    private SerializedProperty animLayerSortIndexObject;

    private int selectEventGroupIndex = -1;
    private int selectEventIndex = -1;

    //UI组件
    private ObjectField previewObj;

    private Toggle tglDefault;
    private Toggle tglAnimLayer;
    private Toggle tglParameter;
    private Toggle tglEvent;
    private Toggle tglDetail;
    private Button btnSave;

    private VisualElement pnlDefault;
    private VisualElement pnlAnimLayer;
    private VisualElement pnlParameter;
    private VisualElement pnlEvent;
    private VisualElement pnlDetail;

    private VisualElement pnlDefaultContent;
    private VisualElement pnlAnimLayerContent;
    private VisualElement pnlParameterContent;
    private VisualElement pnlEventContent;
    private VisualElement pnlDetailContent;

    //默认设置
    private PropertyField defaultAnim;

    //动画层级
    private PropertyField animLayerField;
    private Label animLayerPreview;

    //动画参数
    private PropertyField definitionList;

    //动画事件
    private ListView eventGroupListView;
    private ListView eventListView;
    private TextField groupNameField;

    //详情
    private PropertyField detailField;

    private SpineTouchConfigSOEditorViewData viewData;

    public static void ShowWindow(SpineTouchConfigSO so)
    {
        //只能打开一个窗口
        if (HasOpenInstances<SpineTouchConfigSOEditor>())
        {
            GetWindow<SpineTouchConfigSOEditor>().Close();
        }

        //填入窗口数据
        SpineTouchConfigSOEditorViewData viewData = new()
        {
            assetPath = AssetDatabase.GetAssetPath(so),
            groupSelectIndex = -1,
            eventSelectIndex = -1,
        };
        string jsonData = JsonUtility.ToJson(viewData);
        EditorPrefs.SetString(nameof(SpineTouchConfigSOEditorViewData), jsonData);

        SpineTouchConfigSOEditor wnd = GetWindow<SpineTouchConfigSOEditor>();
        wnd.titleContent = new GUIContent(so.name);

        Debug.Log($"打开数据编辑窗口+{so.skeletonData.name}");
    }

    private void OnDisable()
    {
        viewData.groupSelectIndex = eventGroupListView.selectedIndex;
        viewData.eventSelectIndex = eventListView.selectedIndex;
        string jsonData = JsonUtility.ToJson(viewData);
        EditorPrefs.SetString(nameof(SpineTouchConfigSOEditorViewData), jsonData);
    }

    public void CreateGUI()
    {
        rootVisualElement.Add(m_VisualTreeAsset.Instantiate());

        string jsonData = EditorPrefs.GetString(nameof(SpineTouchConfigSOEditorViewData));
        viewData = JsonUtility.FromJson<SpineTouchConfigSOEditorViewData>(jsonData);
        var so = AssetDatabase.LoadAssetAtPath<SpineTouchConfigSO>(viewData.assetPath);
        Init(so);
    }

    public void Init(SpineTouchConfigSO so)
    {
        so.lastEditSkeletonData = so.skeletonData.name;
        ConfigSO = configSO = so;
        serializedObject = new SerializedObject(configSO);
        definitionListObject = serializedObject.FindProperty("definitions");
        defaultAnimObject = serializedObject.FindProperty("defaultAnimation");
        configGroupsObject = serializedObject.FindProperty("configGroups");
        animLayerSortIndexObject = serializedObject.FindProperty("animLayerSortIndex");

        GetElements();
        RegistElementEvent();
    }

    private void GetElements()
    {
        previewObj = rootVisualElement.Q<ObjectField>("PreviewObj");

        var toolBar = rootVisualElement.Q<Toolbar>();
        tglDefault = rootVisualElement.Q<Toggle>("TglDefault");
        tglAnimLayer = toolBar.Q<Toggle>("TglAnimLayer");
        tglParameter = toolBar.Q<Toggle>("TglParameter");
        tglEvent = toolBar.Q<Toggle>("TglEvent");
        tglDetail = toolBar.Q<Toggle>("TglDetail");
        btnSave = toolBar.Q<Button>("BtnSave");

        var pnlContainer = rootVisualElement.Q<VisualElement>("PnlContainer");
        pnlDefault = rootVisualElement.Q<VisualElement>("PnlDefault");
        pnlAnimLayer = pnlContainer.Q<VisualElement>("PnlAnimLayer");
        pnlParameter = pnlContainer.Q<VisualElement>("PnlParameter");
        pnlEvent = pnlContainer.Q<VisualElement>("PnlEvent");
        pnlDetail = pnlContainer.Q<VisualElement>("PnlDetail");

        pnlDefaultContent = pnlDefault.Q<ScrollView>().contentContainer;
        pnlAnimLayerContent = pnlAnimLayer.Q<ScrollView>().contentContainer;
        pnlParameterContent = pnlParameter.Q<ScrollView>().contentContainer;
        pnlEventContent = pnlEvent.Q<ScrollView>().contentContainer;
        pnlDetailContent = pnlDetail.Q<ScrollView>().contentContainer;

        //默认
        defaultAnim = pnlDefaultContent.Q<PropertyField>("DefaultAnimation");
        //层级
        animLayerField = pnlAnimLayerContent.Q<PropertyField>("AnimLayerField");
        animLayerPreview = pnlAnimLayerContent.Q<Label>("AnimLayerPreview");
        //参数
        definitionList = pnlParameterContent.Q<PropertyField>("DefinitionsList");
        //事件
        var pnlEventGroup = pnlEventContent.Q<VisualElement>("PnlEventGroup");
        eventGroupListView = pnlEventGroup.Q<ListView>("EventGroupListView");
        groupNameField = new TextField("修改名称");
        var btn = new Button(() =>
        {
            if (selectEventGroupIndex == -1 || groupNameField.value == string.Empty)
            {
                return;
            }

            var data = (eventGroupListView.itemsSource[selectEventGroupIndex] as SpineTouchConfigGroup);
            if (data != null)
            {
                data.groupName = groupNameField.value;
                EditorUtility.SetDirty(configSO);
                AssetDatabase.SaveAssetIfDirty(configSO);
                eventGroupListView.Rebuild();
            }
        });
        btn.text = "确定";
        var footContainer = eventGroupListView.Q<Foldout>().Q<VisualElement>().Q<VisualElement>();
        footContainer.Insert(0, btn);
        footContainer.Insert(0, groupNameField);
        eventListView = pnlEventGroup.Q<ListView>("EventListView");
        //详情
        detailField = pnlDetailContent.Q<PropertyField>("DetailField");
    }

    private void RegistElementEvent()
    {
        //工具栏
        tglDefault.value = EditorPrefs.GetBool(ShowDefault, true);
        tglAnimLayer.value = EditorPrefs.GetBool(ShowLayer, true);
        tglParameter.value = EditorPrefs.GetBool(ShowParameter, true);
        tglEvent.value = EditorPrefs.GetBool(ShowEvent, true);
        tglDetail.value = EditorPrefs.GetBool(ShowDetail, true);

        tglDefault.RegisterValueChangedCallback(OnTglDefaultChanged);
        tglAnimLayer.RegisterValueChangedCallback(OnTglAnimLayerChanged);
        tglParameter.RegisterValueChangedCallback(OnTglParameterChanged);
        tglEvent.RegisterValueChangedCallback(OnTglEventChanged);
        tglDetail.RegisterValueChangedCallback(OnTglDetailChanged);
        btnSave.clicked += Save;

        pnlDefault.style.display = EditorPrefs.GetBool(ShowDefault, true) ? DisplayStyle.Flex : DisplayStyle.None;
        pnlAnimLayer.style.display = EditorPrefs.GetBool(ShowLayer, true) ? DisplayStyle.Flex : DisplayStyle.None;
        pnlParameter.style.display = EditorPrefs.GetBool(ShowParameter, true) ? DisplayStyle.Flex : DisplayStyle.None;
        pnlEvent.style.display = EditorPrefs.GetBool(ShowEvent, true) ? DisplayStyle.Flex : DisplayStyle.None;
        pnlDetail.style.display = EditorPrefs.GetBool(ShowDetail, true) ? DisplayStyle.Flex : DisplayStyle.None;

        //默认
        defaultAnimObject.isExpanded = true;
        defaultAnim.BindProperty(defaultAnimObject);
        defaultAnim.Children().First().style.display = DisplayStyle.None;
        //层级
        animLayerField.BindProperty(animLayerSortIndexObject);
        animLayerField.RegisterCallback<ChangeEvent<string>>(evt => OnAnimLayerChanged());
        animLayerField.RegisterCallback<ChangeEvent<int>>(evt => OnAnimLayerChanged());
        UpdateAnimLayerPreview();
        //参数
        definitionList.BindProperty(definitionListObject);
        definitionList.Children().First().style.display = DisplayStyle.None;
        //事件
        eventGroupListView.itemsSource = configSO.configGroups;
        selectEventGroupIndex = eventGroupListView.selectedIndex;
        eventGroupListView.makeItem = EventGroupListViewMakeItem;
        eventGroupListView.bindItem = EventGroupListViewBindItem;
        eventGroupListView.selectedIndicesChanged += OnEventGroupListViewSelect;
        eventGroupListView.itemsAdded += _ => Save();
        eventGroupListView.itemsRemoved += _ => Save();
        eventGroupListView.itemIndexChanged += (i, i1) =>
        {
            selectEventGroupIndex = i1;
            Save();
        };
        eventGroupListView.Rebuild();
        eventListView.makeItem = EventListViewMakeItem;
        eventListView.bindItem = EventListViewBindItem;
        eventListView.selectedIndicesChanged += OnEventListViewSelect;
        eventListView.itemsAdded += _ => AfterEventListViewAddOrRemove();
        eventListView.itemsRemoved += _ => AfterEventListViewAddOrRemove();
        eventListView.itemIndexChanged += (i, i1) =>
        {
            selectEventIndex = i1;
            Save();
        };
        if (viewData.groupSelectIndex != -1)
        {
            eventGroupListView.selectedIndex = viewData.groupSelectIndex;
        }

        UniTask.DelayFrame(2).OnComplete(() =>
        {
            if (viewData.eventSelectIndex != -1)
            {
                eventListView.selectedIndex = viewData.eventSelectIndex;
            }
        }).Forget();

        //详情
        detailField.RegisterCallback<ChangeEvent<string>>(OnDetailFieldChangeString);
    }


    private void Save()
    {
        //有时候触发的时候，数据还没给到SO
        UniTask.DelayFrame(2).OnComplete(() =>
        {
            if (configSO != null)
            {
                serializedObject.ApplyModifiedProperties();
                EditorUtility.SetDirty(configSO);
                AssetDatabase.SaveAssetIfDirty(configSO);
            }
        }).Forget();
    }

    #region UIEvent

    private void AfterEventListViewAddOrRemove()
    {
        selectEventIndex = -1;
        detailField.style.display = DisplayStyle.None;
        UniTask.DelayFrame(2).OnComplete(() =>
        {
            eventListView.selectedIndex = -1;
            detailField.Unbind();
            detailField.style.display = DisplayStyle.None;
            Save();
        }).Forget();
    }

    private CancellationTokenSource animLayerPreviewUpdateTokenSource;

    private void OnAnimLayerChanged()
    {
        animLayerPreviewUpdateTokenSource?.Cancel();
        animLayerPreviewUpdateTokenSource = new CancellationTokenSource();
        UniTask.WaitForSeconds(1).OnComplete(UpdateAnimLayerPreview).Forget();
    }

    private void UpdateAnimLayerPreview()
    {
        Dictionary<string, int> animLayerDict = new Dictionary<string, int>();
        List<SpineAnimLayer> layerIndex = configSO.animLayerSortIndex;

        SpineTouchManager.InitAnimLayerDict(configSO.skeletonData, layerIndex, ref animLayerDict);

        StringBuilder sb = new StringBuilder();

        string changeColor = "#2f72a8";

        foreach (var (key, value) in animLayerDict)
        {
            string label = $"{key}: {value}\n";
            if (layerIndex.Find(l => l.animName == key) != null)
            {
                sb.Append($"<color={changeColor}>{label}</color>");
            }
            else
            {
                sb.Append(label);
            }
        }

        animLayerPreview.text = sb.ToString();
    }

    private void OnDetailFieldChangeString(ChangeEvent<string> evt)
    {
        eventListView.RefreshItem(selectEventIndex);
    }

    private void OnEventListViewSelect(IEnumerable<int> obj)
    {
        //Debug.Log("选中项改变");
        var newIndex = -1;
        if (obj == null || !obj.Any())
        {
            newIndex = -1;
        }
        else
        {
            newIndex = obj.First();
        }

        //等待数据更新到可序列化对象后再更新列表
        UniTask.DelayFrame(2).OnComplete(() =>
        {
            if (newIndex != selectEventIndex)
            {
                var oldIndex = selectEventIndex;
                selectEventIndex = newIndex;
                if (oldIndex != -1)
                {
                    eventListView.RefreshItem(oldIndex);
                }

                eventListView.RefreshItem(selectEventIndex);
            }

            if (selectEventIndex != -1)
            {
                var groupData = configGroupsObject.GetArrayElementAtIndex(selectEventGroupIndex);
                var configData = groupData.FindPropertyRelative("configs");
                if (selectEventIndex < configData.arraySize)
                {
                    var data = configData.GetArrayElementAtIndex(selectEventIndex);
                    data.isExpanded = true;
                    detailField.Unbind();
                    detailField.style.display = DisplayStyle.Flex;
                    detailField.BindProperty(data);
                }
            }
            else
            {
                detailField.style.display = DisplayStyle.None;
            }
        }).Forget();
    }

    private void EventListViewBindItem(VisualElement item, int index)
    {
        var label = item as Label;
        var data = (eventGroupListView.itemsSource[selectEventGroupIndex] as SpineTouchConfigGroup)?.configs[index];
        if (label == null || data == null)
        {
            return;
        }

        label.text = data.skeleton + (selectEventIndex == index ? "   \u261c" : "");
    }

    private VisualElement EventListViewMakeItem()
    {
        var label = new Label();
        return label;
    }

    private void OnEventGroupListViewSelect(IEnumerable<int> obj)
    {
        UniTask.DelayFrame(2).OnComplete(() =>
        {
            #region 更新选中下标

            var enumerable = obj as int[] ?? obj.ToArray();
            var newIndex = !enumerable.Any() ? -1 : enumerable.First();
            if (newIndex == selectEventGroupIndex)
            {
                return;
            }

            var oldIndex = selectEventGroupIndex;
            selectEventGroupIndex = newIndex;
            if (oldIndex != -1)
            {
                eventGroupListView.RefreshItem(oldIndex);
            }

            eventGroupListView.RefreshItem(selectEventGroupIndex);
            //改名框
            groupNameField.value = selectEventGroupIndex != -1 ? configSO.configGroups[selectEventGroupIndex].groupName : string.Empty;

            #endregion

            #region 刷新事件列表

            selectEventIndex = -1;
            eventListView.selectedIndex = -1;
            if (selectEventGroupIndex != -1)
            {
                eventListView.itemsSource = configSO.configGroups[selectEventGroupIndex].configs;
                UnBindDetailField();
                eventListView.Rebuild();
            }
            else
            {
                eventListView.itemsSource = null;
                UnBindDetailField();
                eventListView.Rebuild();
            }

            #endregion
        }).Forget();
    }

    private void UnBindDetailField()
    {
        detailField.style.display = DisplayStyle.None;
    }

    private void EventGroupListViewBindItem(VisualElement item, int index)
    {
        var label = item as Label;
        var data = eventGroupListView.itemsSource[index] as SpineTouchConfigGroup;
        if (label == null || data == null)
        {
            return;
        }

        label.text = data.groupName + (selectEventGroupIndex == index ? "   \u261c" : "");
    }

    private VisualElement EventGroupListViewMakeItem()
    {
        var textField = new Label();
        return textField;
    }

    private void OnTglDetailChanged(ChangeEvent<bool> evt)
    {
        EditorPrefs.SetBool(ShowDetail, evt.newValue);
        pnlDetail.style.display = evt.newValue ? DisplayStyle.Flex : DisplayStyle.None;
    }

    private void OnTglEventChanged(ChangeEvent<bool> evt)
    {
        EditorPrefs.SetBool(ShowEvent, evt.newValue);
        pnlEvent.style.display = evt.newValue ? DisplayStyle.Flex : DisplayStyle.None;
    }

    private void OnTglParameterChanged(ChangeEvent<bool> evt)
    {
        EditorPrefs.SetBool(ShowParameter, evt.newValue);
        pnlParameter.style.display = evt.newValue ? DisplayStyle.Flex : DisplayStyle.None;
    }

    private void OnTglAnimLayerChanged(ChangeEvent<bool> evt)
    {
        EditorPrefs.SetBool(ShowLayer, evt.newValue);
        pnlAnimLayer.style.display = evt.newValue ? DisplayStyle.Flex : DisplayStyle.None;
    }

    private void OnTglDefaultChanged(ChangeEvent<bool> evt)
    {
        EditorPrefs.SetBool(ShowDefault, evt.newValue);
        pnlDefault.style.display = evt.newValue ? DisplayStyle.Flex : DisplayStyle.None;
    }

    #endregion
}

[Serializable]
public class SpineTouchConfigSOEditorViewData
{
    public string assetPath;
    public int groupSelectIndex;
    public int eventSelectIndex;
}